﻿#include "TessellationPass.h"

#include "../../../Common/Singleton.h"
#include "../ResourceManager/Dx2GeometryManager.h"
#include "../ResourceManager/Dx2MaterialManager.h"
#include "../ResourceManager/Dx2RootSignatureManager.h"
#include "../ResourceManager/Dx2ShaderAndLayoutManager.h"

void TessellationPass::BuildRenderItems(std::vector<std::unique_ptr<RenderItem>>& allRitems, UINT& lastObjIndex)
{
    auto quadPatchRitem = std::make_unique<RenderItem>();
    quadPatchRitem->World = MathHelper::Identity4x4();
    quadPatchRitem->TexTransform = MathHelper::Identity4x4();
    quadPatchRitem->ObjCBIndex = lastObjIndex;
    lastObjIndex++;

    quadPatchRitem->Mat = Singleton<Dx2MaterialManager>::Instance()->GetMaterial("tessellation").get();
    quadPatchRitem->Geo = Singleton<Dx2GeometryManager>::Instance()->GetGeometry("tessellationGeo").get();

    quadPatchRitem->PrimitiveType = D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST;
    quadPatchRitem->IndexCount = quadPatchRitem->Geo->DrawArgs["quadpatch"].IndexCount;
    quadPatchRitem->StartIndexLocation = quadPatchRitem->Geo->DrawArgs["quadpatch"].StartIndexLocation;
    quadPatchRitem->BaseVertexLocation = quadPatchRitem->Geo->DrawArgs["quadpatch"].BaseVertexLocation;

    mTessellationRitem = quadPatchRitem.get();
    
    mRenderItems.push_back(quadPatchRitem.get());
    allRitems.push_back(move(quadPatchRitem));
}

void TessellationPass::BuildPSOs(ID3D12Device* device, DXGI_FORMAT BackBufferFormat, DXGI_FORMAT DepthStencilFormat,
    bool _4xMsaaState, UINT _4xMsaaQuality)
{
    D3D12_GRAPHICS_PIPELINE_STATE_DESC tessellationPsoDesc;
    ZeroMemory(&tessellationPsoDesc,sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
	
    tessellationPsoDesc.InputLayout = {Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetTessellationLayout().data(),(UINT)Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetTessellationLayout().size()};
    tessellationPsoDesc.pRootSignature = Singleton<Dx2RootSignatureManager>::Instance()->GetRootSignature(RootSignatureType::Tessellation).Get();
	
    tessellationPsoDesc.VS =
        {
        reinterpret_cast<BYTE*>(Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("tessVS")->GetBufferPointer()),
        Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("tessVS")->GetBufferSize()
    };
	
    tessellationPsoDesc.HS =
        {
        reinterpret_cast<BYTE*>(Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("tessHS")->GetBufferPointer()),
        Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("tessHS")->GetBufferSize()
    };

    tessellationPsoDesc.DS =
       {
        reinterpret_cast<BYTE*>(Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("tessDS")->GetBufferPointer()),
        Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("tessDS")->GetBufferSize()
    };

    tessellationPsoDesc.PS =
       {
        reinterpret_cast<BYTE*>(Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("tessPS")->GetBufferPointer()),
        Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("tessPS")->GetBufferSize()
    };

    
    tessellationPsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
    tessellationPsoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME;
    
    tessellationPsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
    tessellationPsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
    tessellationPsoDesc.SampleMask = UINT_MAX;
    tessellationPsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
    tessellationPsoDesc.NumRenderTargets = 1;
    tessellationPsoDesc.RTVFormats[0] = BackBufferFormat;
    tessellationPsoDesc.SampleDesc.Count = _4xMsaaState? 4:1;
    tessellationPsoDesc.SampleDesc.Quality = _4xMsaaState? (_4xMsaaQuality - 1):0;
    tessellationPsoDesc.DSVFormat = DepthStencilFormat;

    ThrowIfFailed(device->CreateGraphicsPipelineState(&tessellationPsoDesc, IID_PPV_ARGS(&mPso)));
}

void TessellationPass::Draw(ID3D12GraphicsCommandList* cmdList, CD3DX12_GPU_DESCRIPTOR_HANDLE hGpuHandler,
    UINT srvHeapSize, UINT objCBByteSize, UINT matCBByteSize, UINT passCBByteSize, ID3D12Resource* objectCB,
    ID3D12Resource* matCB, ID3D12Resource* passCB, const PassConstants& passValue, ID3D12Resource* OutColorRenderTarget,
    D3D12_CPU_DESCRIPTOR_HANDLE OutColorRenderTargetView, D3D12_CPU_DESCRIPTOR_HANDLE OutDepthStentilView)
{
    cmdList->SetPipelineState(mPso.Get());
    cmdList->SetGraphicsRootSignature(Singleton<Dx2RootSignatureManager>::Instance()->GetRootSignature(RootSignatureType::Tessellation).Get());
    cmdList->SetGraphicsRootConstantBufferView(2,passCB->GetGPUVirtualAddress());

    DrawRenderItem(cmdList,hGpuHandler,srvHeapSize,objCBByteSize,matCBByteSize,objectCB,matCB,mRenderItems);
}
